package com.weilele.mvvm.utils.coroutine


import kotlinx.coroutines.*
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlin.coroutines.AbstractCoroutineContextElement
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext

/**
 * 协程工具类
 */
//yield()函数，让出执行权
/**
 * 创建一个协程作用域
 * context去下面的四个值中的一个
 * [Dispatchers.IO] 工作线程池，依赖于Dispatchers.Default，支持最大并行任务数。
 * [Dispatchers.Unconfined] 无指定派发线程，会根据运行时的上线文环境决定。
 * [Dispatchers.Main] 主线程，这个在不同平台定义不一样，所以需要引入相关的依赖，比如Android平台，需要使用包含MainLooper的handler来向主线程派发。
 * [Dispatchers.Default] 默认线程池，核心线程和最大线程数依赖cpu数量。
 * [Dispatchers.IO]：工作线程池，依赖于Dispatchers.Default，支持最大并行任务数。
 *
 * 感觉和[GlobalScope]创建方式一样
 */

/**
 * 监听协程取消
 * 也可使用waitAny 来监听取消
 */
class MvvmCoroutineExceptionContext(private val handleException: (context: CoroutineContext, exception: Throwable) -> Unit) :
    AbstractCoroutineContextElement(CoroutineExceptionHandler), CoroutineExceptionHandler {
    override fun handleException(context: CoroutineContext, exception: Throwable) {
        handleException.invoke(context, exception)
    }
}
// 可以接收协程内部异常，但是无法监听取消异常
//createCoroutine(MvvmCoroutineException { context, exception ->
//            println()
//        })

fun createCoroutine(context: CoroutineContext = EmptyCoroutineContext): CoroutineScope {
    //创建一个协程作用域，一旦被取消，此对象便不可再使用
    return CoroutineScope(context)
}

@ExperimentalCoroutinesApi
fun createMainCoroutine(): CoroutineScope {
    return MainScope()
}

/**
 * 启动一个协程作用域，并且在子线程运行
 * 创建一个协程
 * [CoroutineStart.DEFAULT]	默认的模式，立即执行协程体
 * [CoroutineStart.LAZY]	只有在需要的情况下运行
 * [CoroutineStart.ATOMIC]	立即执行协程体，但在开始运行之前无法取消
 * [CoroutineStart.UNDISPATCHED]	立即在当前线程执行协程体，直到第一个 suspend 调用
 */
fun globalLaunchOnThread(
    start: CoroutineStart = CoroutineStart.DEFAULT,
    block: suspend CoroutineScope.() -> Unit
): Job {
    return GlobalScope.launch(Dispatchers.Default, start = start, block = block)
}


/**
 * 启动一个协程作用域，并且在子线程运行
 * 创建一个协程
 */
fun <T> globalAsyncOnThread(
    start: CoroutineStart = CoroutineStart.DEFAULT,
    block: suspend CoroutineScope.() -> T
): Deferred<T> {
    return GlobalScope.async(Dispatchers.Default, start = start, block = block)
}

/**
 * 启动一个协程作用域，并且在主线程运行
 * 创建一个协程
 */
fun globalLaunchOnUi(
    start: CoroutineStart = CoroutineStart.DEFAULT,
    block: suspend CoroutineScope.() -> Unit
): Job {
    return GlobalScope.launch(Dispatchers.Main, start = start, block = block)
}

/**
 * 启动一个协程作用域，并且在主线程运行
 * 创建一个协程
 */
fun <T> globalAsyncOnUi(
    start: CoroutineStart = CoroutineStart.DEFAULT,
    block: suspend CoroutineScope.() -> T
): Deferred<T> {
    return GlobalScope.async(Dispatchers.Main, start = start, block = block)
}

/**
 * 切换到主线程
 * 不创建新的协程
 *  withContext开销更低 类似于 async{..}.await()
 */
@Deprecated("使用[withMainThread]", ReplaceWith("使用[withMainThread]"))
suspend fun <T> switchToUi(block: suspend CoroutineScope.() -> T): T {
    return withMainThread(block)
}

suspend fun <T> withMainThread(block: suspend CoroutineScope.() -> T): T {
    return withContext(Dispatchers.Main, block)
}

/**
 * 切换到子线程
 * 不创建新的协程
 * withContext开销更低 类似于 async{..}.await()
 */
@Deprecated("使用[withThread]", ReplaceWith("使用[withThread]"))
suspend fun <T> switchToThread(block: suspend CoroutineScope.() -> T): T {
    return withThread(block)
}

suspend fun <T> withThread(block: suspend CoroutineScope.() -> T): T {
    return withContext(Dispatchers.Default, block)
}

/**
 * 创建Mutex对象
 */
fun createMutex(locked: Boolean = false) = Mutex(locked)

/**
 * 代码加锁运行
 * 非阻塞
 */
suspend fun <T> withLock(mutex: Mutex, owner: Any? = null, action: () -> T): T {
    return mutex.withLock(owner, action)
}

/**
 * 启动新的协程，代码运行在主线程
 * 没有自定义返回值
 * launch和async区别，一个有返回值，一个没有
 * start可以指定执行时机
 * async是可控的（await()阻塞当前协程，不往下执行。
 *                在定义的时候async已经开始运行了，
 *                await()只是等待执行完毕再向下执行，否则会继续走下面的逻辑）
 */
fun CoroutineScope.launchOnUi(
    start: CoroutineStart = CoroutineStart.DEFAULT,
    block: suspend CoroutineScope.() -> Unit
): Job {
    return launch(Dispatchers.Main, start = start, block = block)
}


/**
 * 启动新的协程，代码运行在主线程
 * 有自定义返回值
 *  start可以指定执行时机
 *  launch和async区别，一个有返回值，一个没有
 * async是可控的（await()阻塞当前协程，不往下执行。
 *                在定义的时候async已经开始运行了，
 *                await()只是等待执行完毕再向下执行，否则会继续走下面的逻辑）
 */
fun <T> CoroutineScope.asyncOnUi(
    start: CoroutineStart = CoroutineStart.DEFAULT,
    block: suspend CoroutineScope.() -> T
): Deferred<T> {
    return async(Dispatchers.Main, start = start, block = block)
}

/**
 * 启动新的协程，代码运行在子线程
 * 没有自定义返回值
 *  start可以指定执行时机
 *  launch和async区别，一个有返回值，一个没有
 * async是可控的（await()阻塞当前协程，不往下执行。
 *                在定义的时候async已经开始运行了，
 *                await()只是等待执行完毕再向下执行，否则会继续走下面的逻辑）
 */
fun CoroutineScope.launchOnThread(
    start: CoroutineStart = CoroutineStart.DEFAULT,
    block: suspend CoroutineScope.() -> Unit
): Job {
    return launch(Dispatchers.Default, start = start, block = block)
}

/**
 * 启动新的协程，代码运行在子线程
 * 有自定义返回值
 *  start可以指定执行时机
 *  launch和async区别，一个有返回值，一个没有
 * async是可控的（await()阻塞当前协程，不往下执行。
 *                在定义的时候async已经开始运行了，
 *                await()只是等待执行完毕再向下执行，否则会继续走下面的逻辑）
 */
fun <T> CoroutineScope.asyncOnThread(
    start: CoroutineStart = CoroutineStart.DEFAULT,
    block: suspend CoroutineScope.() -> T
): Deferred<T> {
    return async(Dispatchers.Default, start = start, block = block)
}

/**
 * 将异步代码写成同步调用示例
 */
suspend inline fun <T> awaitAny(crossinline block: (CancellableContinuation<T>) -> Unit): T {
    return suspendCancellableCoroutine(block)
}

/**
 * 多个结果回调例子
 */
fun <T, T1> CoroutineScope.multipleAsync(
    run: suspend CoroutineScope.() -> T,
    run1: suspend CoroutineScope.() -> T1,
    result: Function2<T, T1, Unit>
) {
    launch {
        val t = async { run.invoke(this) }
        val t1 = async { run1.invoke(this) }
        val r = t.await()
        val r1 = t1.await()
        result.invoke(r, r1)
    }
}

private suspend fun <T> awaitAny() = suspendCancellableCoroutine<T> { continuation ->
    continuation.invokeOnCancellation {
        //接收异常
    }
    Thread.sleep(10000)
    //恢复调用
//    continuation.resume()
    //异常
//    continuation.resumeWithException()
}
/*************************************列子**************************/
/**
 * switchToXx的使用
 * 按照顺序执行
 * 1-2-3-4-5-6-7-8
 */
private fun main() {
    globalLaunchOnUi {
        val timeS = System.currentTimeMillis()
        val s1 = switchToThread {
            println("1")
            delay(1000)
            println("2")
            100
            switchToThread {
                println("3")
                delay(1000)
                println("4")
                110
            }
        }
        val s2 = switchToThread {
            println("5")
            delay(1000)
            println("6")
            100
        }
        println("7:${s1},${s2},${System.currentTimeMillis() - timeS}")
    }
}

/**
 * println打印函数不会等待s1 和s2执行完毕才执行，会优先执行
 */
private fun test2() {
    globalLaunchOnThread {
        val timeS = System.currentTimeMillis()
        val s1 = launch {
            println("1")
            delay(1000)
            println("")
        }
        val s2 = launch {
            println("2")
            delay(1000)
            println("")
            100
        }
        println("3:${s1},${s2},${System.currentTimeMillis() - timeS}")
    }
}
/*
val job = createCoroutine(
    context = MvvmCoroutineExceptionContext { context, exception ->
        println("---------------createCoroutine-------${context}---------------${exception}")
    }
).launch(context = MvvmCoroutineExceptionContext { context, exception ->
    println("----------------------${context}---------------${exception}")
}) {
    launch(context = MvvmCoroutineExceptionContext { context, exception ->
        println("-------------launch---------${context}---------------${exception}")
    }) {
        println("---launch1-----")
        delay(3000)
    }
    launch {
        println("---launch2-----")
        delay(2000)
        println("----launch end-----")
    }
}
job.invokeOnCompletion {
    println("-----Completion  ${it}----")
}*/
